package com.dynamo.transport.network.practise.channel.socket.nio;

import com.dynamo.transport.network.practise.channel.*;
import com.dynamo.transport.network.practise.channel.socket.AbstractSocketChannel;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;

/**
 * @author duanyimiao
 * @create 2018-12-18 3:32 PM
 * @description
 **/
public class NioChannelSink extends AbstractChannelSink {

    private Queue<MessageEvent> writeBufferQueue = new ConcurrentLinkedQueue<>();

    @Override
    public void eventSunk(ChannelPipeline pipeline, ChannelEvent e) {
        if (e instanceof ChannelStateEvent) {
            try {
                ChannelStateEvent event = (ChannelStateEvent) e;
                if (event.getValue() == Channel.BIND) {
                    System.out.println("bind eventSunk=" + e);
                    //绑定端口
                    NioServerSocketChannel channel = (NioServerSocketChannel) e.getChannel();
                    //真正绑定到某个端口上
                    channel.channel.socket().bind(channel.getLocalAddress());
                    System.out.println("bind success");
                    //通过future通知绑定成功
                    //e.future().setSuccess();
                } else if (event.getValue() == Channel.CONNECT) {
                    //客户端连接服务端
                    AbstractSocketChannel socketChannel = (AbstractSocketChannel) e.getChannel();

                    socketChannel.channel.connect(socketChannel.getRemoteAddress());

                    System.out.println("connecting to server");

                }

            } catch (Exception e1) {
                e1.printStackTrace();
                e.future().setFail(e1);
            }

        }

        if (e instanceof MessageEvent) {
            acceptMessageEvent((MessageEvent) e);
        }
    }

    private void acceptMessageEvent(MessageEvent event) {
        //先放到writeBufferQueue中，然后监听写事件，当写事件就绪时才从中取出写到 nio Channel中

        writeBufferQueue.offer(event);
        try {
            //先直接将nio ByteBuffer写入到nio Channel中，后面在优化，走队列，将ChannelBuffer转换成ByteBuffer
            ByteBuffer buffer = (ByteBuffer) event.getMsg();
            //切换到写模式
            buffer.flip();
            ((AbstractSocketChannel) event.getChannel()).channel.write(buffer);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        try {
            SocketChannel s = SocketChannel.open();
            s.connect(new InetSocketAddress("127.0.0.1", 1890));
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}
